package com.zonerobotics.zBotAPI.protocolMapping;

import java.util.HashMap;


/**
 * This class holds all the mapping information to map requests
 * to hardware memory locations based off the "name" string of the
 * value. 
 * @author Michael McCarty
 * Feb 2, 2013
 */
public class VarMapping {
	public HashMap<String, VarMap> mappingVars;
	HashMap<Integer, String> positionLookup;
	public int totalSizeInBytes = 0;
	public int totalVars = 0;

	/**
	 * this sets up the hashmap
	 */
	public VarMapping(int version)
	{
		mappingVars = new HashMap<String, VarMap>();
		positionLookup = new HashMap<Integer, String>();
		initMappingForVersion(version);
	}
	
	/**
	 * This adds the map to the current var mapping
	 * 
	 * @param vm
	 * var map to add
	 * @return 
	 * varmapping object if successfull;
	 */
	public VarMapping addMapping(VarMap vm)
	{
		this.mappingVars.put(vm.name, vm);
		positionLookup.put(vm.position, vm.name);
		return this;
	}
	
	public boolean elementExists(String name)
	{
		return mappingVars.containsKey(name);
	}
	
	public boolean elementExists(VarMap vm)
	{
		return mappingVars.containsKey(vm.name);
	}
	
	/**
	 * this returns the offset in bytes from 0 in the hardware's 
	 * memory
	 * @param name
	 * name of the variable you are looking for
	 * @return
	 * offset within memory of hardware in bytes
	 */
	public int getOffset(String name)
	{
		return this.mappingVars.get(name).bitOffset;
	}
	
	/**
	 * this returns the position of the variable in respect 
	 * to all the others, the rank 
	 * @param name
	 * name of the variable 
	 * @return
	 * offset or rank irrespective of size
	 */
	public int getPosition(String name)
	{
		return this.mappingVars.get(name).position;
	}

	/**
	 * returns the string name from the position
	 * @param position
	 * @return
	 */
	public String getNameFromPosition(int position)
	{
		return positionLookup.get(position);
	}
	
	/**
	 * this will return the actual byte offset needed for the packet
	 * based off the position
	 * @param position
	 * @return
	 */
	public int getByteOffsetFromPosition(int position)
	{
		return (mappingVars.get(getNameFromPosition(position)).bitOffset/8);
	}
	
	public int getSizeFromPosition(int position)
	{
		return mappingVars.get(getNameFromPosition(position)).size;
	}
	
	/**
	 * returns the access level or expected use of the
	 * variable in the hardware, this could be rw, ro 
	 * or other values, see enum for more details
	 * @param name
	 * name of the variable 
	 * @return
	 * Access level of variable
	 */
	public VarAccessLevel getVarAccessLevel(String name)
	{
		return this.mappingVars.get(name).AccessType;
	}
	
	/**
	 * get the byte size of the variable
	 * @param name
	 * name of variable
	 * @return
	 * size in bytes
	 */
	public int getByteSize(String name)
	{
		return this.mappingVars.get(name).size/8;
	}
	
	public void initMappingForVersion(int Version)
	{
		VarMap.resetVarMap();
		
		switch(Version)
		{
			case 1:
				// Environmental
				this.addMapping( new VarMap(VarAccessLevel.READ_ONLY, 16, "modelInfo"));		// type of model, software version
				this.addMapping( new VarMap(VarAccessLevel.READ_ONLY, 16, "versionInfo"));		// version number
				this.addMapping( new VarMap(VarAccessLevel.READ_ONLY, 32, "status"));			// current status including errors
				this.addMapping( new VarMap(VarAccessLevel.READ_ONLY, 32, "update"));			// zbot requests you update something 
					
					// adc conversions
				this.addMapping( new VarMap(VarAccessLevel.READ_ONLY, 32, "ADCIN1"));			// 
				this.addMapping( new VarMap(VarAccessLevel.READ_ONLY, 32, "ADCIN2"));			// 
				this.addMapping( new VarMap(VarAccessLevel.READ_ONLY, 32, "FQ1"));			// captures the frequency on this pin

					// ReadWrite Variables, we will read often, write rarely

					// Environmental
				this.addMapping( new VarMap(VarAccessLevel.READ_WRITE, 32, "gpioRead"));	  	// live values of readable gpio
				this.addMapping( new VarMap(VarAccessLevel.READ_WRITE, 32, "seconds"));	  	// current seconds 
				this.addMapping( new VarMap(VarAccessLevel.READ_WRITE, 32, "milliseconds"));  	// current milliseconds
				this.addMapping( new VarMap(VarAccessLevel.READ_WRITE, 32, "i2cRXBuff"));		// last rx command from i2c

					// some space for a few future use vars
				this.addMapping( new VarMap(VarAccessLevel.READ_WRITE, 32, "FutureR1"));			//	future use ? 
				this.addMapping( new VarMap(VarAccessLevel.READ_WRITE, 32, "FutureR2"));			//	future use ? 
					
					// WRITE VARIABLES (CAN BE READ ALSO) ***********************

				this.addMapping( new VarMap(VarAccessLevel.WRITE_ONLY, 32, "enabled"));		// what perih are enabled
				this.addMapping( new VarMap(VarAccessLevel.WRITE_ONLY, 32, "gpioWrite"));		// write to gpio 
					// pwm motor control ? 
				this.addMapping( new VarMap(VarAccessLevel.WRITE_ONLY, 8, "PWMOUTCH1Duty"));	   	// 
				this.addMapping( new VarMap(VarAccessLevel.WRITE_ONLY, 8, "PWMOUTCH2Duty"));
				this.addMapping( new VarMap(VarAccessLevel.WRITE_ONLY, 8, "PWMOUTCH3Duty"));
				this.addMapping( new VarMap(VarAccessLevel.WRITE_ONLY, 8, "PWMOUTCH4Duty"));
				this.addMapping( new VarMap(VarAccessLevel.WRITE_ONLY, 8, "PWMOUTCH5Duty")); 
				this.addMapping( new VarMap(VarAccessLevel.WRITE_ONLY, 8, "PWMOUTCH6Duty")); 
				this.addMapping( new VarMap(VarAccessLevel.WRITE_ONLY, 8, "PWMOUTCH7Duty")); 
				this.addMapping( new VarMap(VarAccessLevel.WRITE_ONLY, 8, "PWMOUTCH8Duty"));  
				this.addMapping( new VarMap(VarAccessLevel.WRITE_ONLY, 32, "PWMOUTFQ"));		   	// frequency of pwm
					// video 
				this.addMapping( new VarMap(VarAccessLevel.READ_ONCE, 16, "VideoWidth"));
				this.addMapping( new VarMap(VarAccessLevel.READ_ONCE, 16, "VideoHeight")); // todo implement changing !
				this.addMapping( new VarMap(VarAccessLevel.READ_ONCE, 8, "VideoBPP"));
				this.addMapping( new VarMap(VarAccessLevel.READ_ONCE, 8, "VideoFmt"));
				this.addMapping( new VarMap(VarAccessLevel.READ_ONCE, 8, "VideoStat"));
					 
					// not used yet
				this.addMapping( new VarMap(VarAccessLevel.READ_ONCE, 32, "i2cTXBuff"));	   	// data sent to i2c bus
				this.addMapping( new VarMap(VarAccessLevel.READ_ONCE, 32, "DAC1"));			// dac1 
				this.addMapping( new VarMap(VarAccessLevel.READ_ONCE, 32, "DAC2"));			// dac2 
					// some space for a few future use vars
				this.addMapping( new VarMap(VarAccessLevel.READ_ONCE, 32, "FutureW1"));		//	future use ? 
				this.addMapping( new VarMap(VarAccessLevel.READ_ONCE, 32, "FutureW2"));		//	future use ? 
			
			break;
			
			default:
				break;
		}// end switch
		
		for(VarMap m: mappingVars.values())
		{
			this.totalSizeInBytes += m.size;
			totalVars++;
		}
	}
	
	
}
